package com.ctshk.common.service.support;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ctshk.common.constant.ErrCode;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.IBaseEntity;
import com.ctshk.common.model.PageReq;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.service.utils.ApplicationContextUtil;
import com.ctshk.common.utils.Assist;
import com.ctshk.common.utils.SnowflakeIdWorker;

/**
 * 基础service
 * 
 * @author Qiaoxin.Hong
 *
 */
public interface BaseService {
	
	/**
	 * 取得日志打印器
	 * @return
	 */
	default Logger getLogger() {
		return LoggerFactory.getLogger(getClass());
	}

	/**
	 * 取得ApplicationContext
	 * @return
	 */
	default ApplicationContext getContext() {
		return ApplicationContextUtil.getApplicationContext();
	}
	
	/**
	 * 参数验证
	 * @param obj
	 */
	default void validateArgs(Object obj) {
		if (obj == null) return;
		
		Validator validator = getContext().getBean(Validator.class);
		Assist.notNull(validator);
		
		Set<ConstraintViolation<Object>> constraintViolations = validator.validate(obj);
		if (Assist.isNotEmpty(constraintViolations)) {
			ConstraintViolation<Object> violation = constraintViolations.iterator().next();
//			throw new BusinessException(SystemError.SYS_409, violation.getPropertyPath().toString());
			throw new BusinessException(SystemError.SYS_430, violation.getMessage());
		}
	}
	
	/**
	 * 验证不能为null
	 * @param val
	 */
	default void validateNotNull(Object...vals) {
		for (Object val : vals) {
			if (val == null)
				throw new BusinessException(SystemError.SYS_402);
		}
	}
	
	/**
	 * 验证不能为null
	 * @param val
	 */
	default <T> T validateNotNullFn(T val) {
		validateNotNull(val);
		return val;
	}
	
	/**
	 * 验证不能为blank
	 * @param vals
	 */
	default void validateNotBlank(String...vals) {
		for (String val : vals) {
			if (Assist.isBlank(val))
				throw new BusinessException(SystemError.SYS_402);
		}
	}
	
	/**
	 * 验证不能为null
	 * @param val
	 */
	default <T> T notNull(T val, ErrCode errCode, Object... format) {
		if (val == null)
			throw new BusinessException(errCode, format);
		return val;
	}
	
	/**
	 * 验证不能为empty
	 * @param val
	 */
	default void notEmpty(Collection<?> val, ErrCode errCode, Object... format) {
		if (Assist.isEmpty(val))
			throw new BusinessException(errCode, format);
	}
	
	
	
	
	/**
	 * 创建主键编号
	 * @return
	 */
	default Long newId() {
		return SnowflakeIdWorker.nextId();
	}
	
	/**
	 * 创建一个新增业务的实体，默认设置一些公共属性
	 * @param <T>
	 * @return
	 */
	default <T extends IBaseEntity> T newCreateEntity(Class<T> clazz) {
		return newCreateEntity(clazz, null);
	}
	
	/**
	 * 创建一个新增业务的实体，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newCreateEntity(Class<T> clazz, Object orig) {
		return newCreateEntity(clazz, orig, null);
	}
	
	/**
	 * 创建一个新增业务的实体，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newCreateEntity(Class<T> clazz, Object orig, TokenUser tokenUser) {
		return newCreateEntityUserId(clazz, orig, getTokenUserId(tokenUser));
	}
	
	/**
	 * 创建一个新增业务的实体，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newCreateEntityUserId(Class<T> clazz, Object orig, Long userId) {
		T entity = Assist.newInstance(clazz);
		
		if (orig != null)
			Assist.copyProperties(orig, entity);
		
		fillCreateEntityUserId(entity, userId);
		
		return entity;
	}
	
	/**
	 * 创建一个修改业务的实体，默认设置一些公共属性
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	default <T extends IBaseEntity> T newUpdateEntity(Class<T> clazz) {
		return newUpdateEntity(clazz, null);
	}
	
	/**
	 * 创建一个修改业务的实体，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newUpdateEntity(Class<T> clazz, Object orig) {
		return newUpdateEntity(clazz, orig, null);
	}
	
	/**
	 * 创建一个修改业务的实体，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newUpdateEntity(Class<T> clazz, Object orig, TokenUser tokenUser) {
		return newUpdateEntityUserId(clazz, orig, getTokenUserId(tokenUser));
	}
	
	/**
	 * 创建一个修改业务的实体，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newUpdateEntityUserId(Class<T> clazz, Object orig, Long userId) {
		T entity = Assist.newInstance(clazz);

		if (orig != null)
			Assist.copyProperties(orig, entity);

		fillUpdateEntityUserId(entity, userId);
		
		return entity;
	}
	
	/**
	 * 创建修改业务的实体列表，默认设置一些公共属性，并复制orig属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> List<T> newUpdateEntityListUserId(Class<T> clazz, Collection<?> origList, Long userId) {
		return Assist.forEachToList(origList, orig -> newUpdateEntityUserId(clazz, orig, userId));
	}
	
	/**
	 * 创建一个软删业务的实体，默认设置一些公共属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newDeleteEntity(Class<T> clazz) {
		return newDeleteEntity(clazz, null);
	}
	
	/**
	 * 创建一个软删业务的实体，默认设置一些公共属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newDeleteEntity(Class<T> clazz, Long id) {
		return newDeleteEntity(clazz, id, null);
	}
	
	/**
	 * 创建一个软删业务的实体，默认设置一些公共属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newDeleteEntity(Class<T> clazz, Long id, TokenUser tokenUser) {
		return newDeleteEntityUserId(clazz, id, getTokenUserId(tokenUser));
	}
	
	/**
	 * 创建一个软删业务的实体，默认设置一些公共属性
	 * @param <T>
	 * @param clazz
	 * @param orig
	 * @return
	 */
	default <T extends IBaseEntity> T newDeleteEntityUserId(Class<T> clazz, Long id, Long userId) {
		T entity = Assist.newInstance(clazz);
		entity.setId(id);
		entity.setModifiedId(userId);
		entity.setGmtModified(LocalDateTime.now());
		entity.setIsDeleted(IsDeletedCode.YES.getCode());
		return entity;
	}
	
	/**
	 * 设置新增业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillCreateEntity(T entity) {
		return fillCreateEntity(entity, null);
	}
	
	/**
	 * 设置新增业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillCreateEntity(T entity, TokenUser tokenUser) {
		return fillCreateEntityUserId(entity, getTokenUserId(tokenUser));
	}
	
	/**
	 * 设置新增业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> List<T> fillCreateEntity(Collection<T> list, TokenUser tokenUser) {
		return Assist.forEachToList(list, entity -> fillCreateEntity(entity, tokenUser));
	}
	
	/**
	 * 设置新增业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> List<T> fillCreateEntityUserId(Collection<T> list, Long userId) {
		return Assist.forEachToList(list, entity -> fillCreateEntityUserId(entity, userId));
	}
	
	/**
	 * 设置新增业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillCreateEntityUserId(T entity, Long userId) {
		if (entity != null) {
			entity.setId(newId());
			entity.setCreateId(userId);
			entity.setModifiedId(userId);
			entity.setGmtCreate(LocalDateTime.now());
			entity.setGmtModified(LocalDateTime.now());
			entity.setIsDeleted(IsDeletedCode.NO.getCode());
		}
		return entity;
	}
	
	/**
	 * 设置修改业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillUpdateEntity(T entity) {
		return fillUpdateEntity(entity, null);
	}
	
	/**
	 * 设置修改业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillUpdateEntity(T entity, TokenUser tokenUser) {
		return fillUpdateEntityUserId(entity, getTokenUserId(tokenUser));
	}
	
	/**
	 * 设置修改业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillUpdateEntity(T entity, Object orig, TokenUser tokenUser) {
		return fillUpdateEntityUserId(entity, orig, getTokenUserId(tokenUser));
	}
	
	/**
	 * 设置修改业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillUpdateEntityUserId(T entity, Long userId) {
		if (entity != null) {
			entity.setModifiedId(userId);
			entity.setGmtModified(LocalDateTime.now());
		}
		return entity;
	}
	
	/**
	 * 设置修改业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillUpdateEntityUserId(T entity, Object orig, Long userId) {
		if (entity != null) {
			if (orig != null)
				Assist.copyProperties(orig, entity);
			
			entity.setModifiedId(userId);
			entity.setGmtModified(LocalDateTime.now());
		}
		return entity;
	}
	
	/**
	 * 设置删除业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillDeleteEntity(T entity) {
		return fillDeleteEntity(entity, null);
	}
	
	/**
	 * 设置删除业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillDeleteEntity(T entity, TokenUser tokenUser) {
		return fillDeleteEntityUserId(entity, getTokenUserId(tokenUser));
	}
	
	/**
	 * 设置删除业务实体的公共属性
	 * @param <T>
	 * @param entity
	 * @return
	 */
	default <T extends IBaseEntity> T fillDeleteEntityUserId(T entity, Long userId) {
		if (entity != null) {
			entity.setIsDeleted(IsDeletedCode.YES.getCode());
			entity.setModifiedId(userId);
			entity.setGmtModified(LocalDateTime.now());
		}
		return entity;
	}
	
	/**
	 * 创建默认成功的结果集
	 * @return
	 */
	default <T> Result<T> newResult() {
		return new Result<>();
	}
	
	/**
	 * 创建默认成功的结果集
	 * @return
	 */
	default <T> Result<T> newResult(T data) {
		return new Result<T>(data);
	}
	
	/**
	 * 创建分页结果集
	 * @return
	 */
	default <T> Result<PageResponse<T>> newPageResult() {
		return newPageResult(new Page<>());
	}
	
	/**
	 * 创建分页结果集
	 * @return
	 */
	default <T> Result<PageResponse<T>> newPageResult(IPage<T> page) {
		return newPageResult(page, page.getRecords());
	}
	
	/**
	 * 创建分页结果集
	 * @return
	 */
	default <T> Result<PageResponse<T>> newPageResult(IPage<?> page, List<T> list) {
		PageResponse<T> pageResponse = new PageResponse<>(list,page.getCurrent() == 1,
				page.getTotal() <= (page.getCurrent() * page.getSize()),
						page.getTotal(), page.getCurrent(), page.getSize());
		return newResult(pageResponse);
	}
	
	/**
	 * 从TokenUser取得用户ID
	 * @param tokenUser
	 * @return
	 */
	default Long getTokenUserId(TokenUser tokenUser) {
		if (tokenUser == null) return null;
		return tokenUser.getId();
	}
	
	/**
	 * 创建用户
	 * @param userId
	 * @return
	 */
	default TokenUser createFakeTokenUser(Long userId) {
		TokenUser tokenUser = new TokenUser();
		tokenUser.setId(userId);
		return tokenUser;
	}
	
	/**
	 * 对象转换
	 * @param <T>
	 * @param src
	 * @param destClass
	 * @return
	 */
	default <T> T toBean(Object src, Class<T> destClass) {
		return Assist.toBean(src, destClass);
	}
	
	/**
	 * 对象列表转换
	 * @param <T>
	 * @param srcList
	 * @param destClass
	 * @return
	 */
	default <T> List<T> toBeanList(Collection<?> srcList, Class<T> destClass) {
		return Assist.toBeanList(srcList, destClass);
	}
	
	/**
	 * 转json
	 * @param obj
	 * @return
	 */
	default String toJson(Object obj) {
		return obj == null ? "{}" : JSON.toJSONString(obj);
	}
	/**
	 * 创建异常
	 * @param error
	 * @param format
	 * @return
	 */
	default BusinessException newException(SystemError error, Object... format) {
		return new BusinessException(error, format);
	}
	
	/**
	 * 创建异常
	 * @param error
	 * @param format
	 * @return
	 */
	default void throwException(SystemError error, Object... format) {
		throw newException(error, format);
	}
	
	/**
	 * 创建分页对象
	 * @param <T>
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	default <T> IPage<T> newPage(PageReq req) {
		Assist.notNull(req);
		return newPage(req.getPageNo(), req.getPageSize());
	}
	
	/**
	 * 创建分页对象
	 * @param <T>
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	default <T> IPage<T> newPage(int pageNo, int pageSize) {
		return new Page<>(pageNo, pageSize);
	}
	
	/**
	 * 计算总页数，默认0
	 * @param pageResponse
	 * @return
	 */
	default long calcPages(PageResponse<?> pageResponse) {
		if (pageResponse == null) 
			return 0;
		return (long) Math.ceil((double) pageResponse.getTotal() / pageResponse.getPageSize());
	}
	
	
}
